﻿using System;
using System.Collections.Generic;
using System.Linq;
using HK.Core.Extend;
using HK.Core.GUIEx.Protocol.Attribute;
using HK.Core.Utils;
using HK.Editor.Common;
using HK.Editor.GUIEx.Data;
using HK.Editor.GUIEx.Styles;
using HK.Editor.GUIEx.TreeView.Control;
using HK.Editor.GUIEx.Window;
using HK.Editor.Network.Download.Data;
using HK.Editor.Network.Download.Protocol.Window;
using HK.Editor.Utils;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;

namespace HK.Editor.Network.Download.Window
{
    public class DownloadVerifyWindow : MultiColsWindow<DownloadVerifyWindow, WindowConf, DownloadVerifyData, DownloadVerifyElement>, IDownloadVerifyWindow<DownloadVerifyWindow, WindowConf, DownloadVerifyData, DownloadVerifyElement>
    {
        
	    
        
#region Menu

		/// <summary>
		/// 显示宏定义窗口.
		/// </summary>
		[MenuItem(EditorConst.MENU_TXT_TOOL_DOWNLOAD_VERIFY, false, EditorConst.MENU_PRIORITY_DOWNLOAD_VERIFY)]
		static void ShowWindow()
		{
		    var conf = WindowConf.Create("验证下载", new Rect(0, 0, 800, 600), (int)GUIOperateOptions.DownloadVerifyWindow);
		    // 显示窗体
		    ShowWindow(conf, true, true);
		}

#endregion

		/// <summary>
		/// 初始化数据.
		/// </summary>
		protected override bool InitData()
		{
			if (!base.InitData())
			{
				return false;
			}
					
			// 导出
			Export();
			return true;
		}

		// private string GetDefaultDownloadDir()
		// {
		// }
	    
        /// <summary>
        /// 下载状态
        /// </summary>
        public DownloadVerifyState State { get; private set; } = DownloadVerifyState.Idle;
        
#region Size&Rect

        private static readonly float IdWidth = 30.0f;
        private static readonly float DownloadFileWidth = 400.0f;
        private static readonly float CrcCodeWidth = 80.0f;
        private static readonly float DataSizeWidth = 80.0f;
        private static readonly float ProgressWidth = 80.0f;

        private static readonly float HeaderHeight = (SingleLineHeight + VerticalSpacing) * 3 + VerticalSpacing;
        private static readonly float LocalTmpDirHeight = SingleLineHeight + VerticalSpacing * 3;
        
        private static readonly float DownloadDirLabelWidth = 120.0f;
        private static readonly float DownloadBrowseBtnWidth = EditorConst.BtnWidthMid;


#endregion
        
#region TableTree
        
        protected override MultiColumnHeaderState GenerateTableHeader(float iWidth)
        {
	        var operationWidth = iWidth - IdWidth - DownloadFileWidth - CrcCodeWidth - DataSizeWidth - ProgressWidth;
	        operationWidth = 120.0f <= operationWidth ? 120.0f : operationWidth;
            
            var columns = new[] 
			{
				new MultiColumnHeaderState.Column 
				{
					headerContent = new GUIContent("Id"),
					contextMenuText = "Id",
					headerTextAlignment = TextAlignment.Center,
					sortedAscending = true,
					sortingArrowAlignment = TextAlignment.Right,
					width = IdWidth, 
					minWidth = IdWidth * 0.6f,
					maxWidth = IdWidth * 2.0f,
					autoResize = false,
					allowToggleVisibility = true
				},
				new MultiColumnHeaderState.Column 
				{
					headerContent = new GUIContent("文件"),
					headerTextAlignment = TextAlignment.Left,
					sortedAscending = true,
					sortingArrowAlignment = TextAlignment.Right,
					width = DownloadFileWidth, 
					minWidth = DownloadFileWidth * 0.6f,
					maxWidth = DownloadFileWidth * 1.5f,
					autoResize = false,
					allowToggleVisibility = false
				},
				new MultiColumnHeaderState.Column 
				{
					headerContent = new GUIContent("Crc"),
					headerTextAlignment = TextAlignment.Center,
					sortedAscending = true,
					sortingArrowAlignment = TextAlignment.Right,
					width = CrcCodeWidth,
					minWidth = CrcCodeWidth * 0.6f,
					maxWidth = CrcCodeWidth * 1.5f,
					autoResize = true
				},
				new MultiColumnHeaderState.Column 
				{
					headerContent = new GUIContent("大小"),
					headerTextAlignment = TextAlignment.Center,
					sortedAscending = true,
					sortingArrowAlignment = TextAlignment.Right,
					width = DataSizeWidth,
					minWidth = DataSizeWidth * 0.6f,
					maxWidth = DataSizeWidth * 1.5f,
					autoResize = true,
					allowToggleVisibility = true
				},
				new MultiColumnHeaderState.Column 
				{
					headerContent = new GUIContent("进度"),
					headerTextAlignment = TextAlignment.Center,
					canSort = false,
					width = ProgressWidth,
					minWidth = ProgressWidth * 0.6f,
					maxWidth = ProgressWidth * 1.5f,
					autoResize = true
				},
				new MultiColumnHeaderState.Column 
				{
					headerContent = new GUIContent("操作"),
					headerTextAlignment = TextAlignment.Center,
					canSort = false,
					width = operationWidth,
					minWidth = operationWidth * 0.6f,
					maxWidth = operationWidth * 1.5f,
					autoResize = true
				}
			};
            
			var state =  new MultiColumnHeaderState(columns);
			return state;
        }
        
        /// <summary>
        /// 树枝列表
        /// </summary>
        protected override IList<DownloadVerifyElement> Branches => Data.Targets;

        /// <summary>
        /// 列数
        /// </summary>
        protected override int ColumnsCount => Enum.GetValues(typeof(DownloadVerifyColumns)).Length;

#region Sort

        /// <summary>
        /// 排序选项
        /// </summary>
        private DownloadVerifySortOption[] _sortOptions = new []
        {
            DownloadVerifySortOption.Id,
            DownloadVerifySortOption.Name,
            DownloadVerifySortOption.Crc,
            DownloadVerifySortOption.Size
        };
        
        /// <summary>
        /// 根据列排序
        /// </summary>
        /// <param name="iHeaderColumns">头部列</param>
        /// <param name="iRoot">根节点</param>
        protected override void SortByColumns(MultiColumnHeader iHeaderColumns, TreeViewItem iRoot)
        {
            if(null == iHeaderColumns || null == iRoot) return;
            var sortedColumns = iHeaderColumns.state.sortedColumns;
            if (0 >= sortedColumns.Length) return;

            var rows = iRoot.children.Cast<TreeViewRow<DownloadVerifyElement>>();
            var orderedQuery = InitialOrder (iHeaderColumns, rows, sortedColumns);
            for (var idx = 1; idx < sortedColumns.Length; ++idx)
            {
                var sortOption = _sortOptions[sortedColumns[idx]];
                var ascending = iHeaderColumns.IsSortedAscending(sortedColumns[idx]);
                switch (sortOption)
                {
                    case DownloadVerifySortOption.Id:
                        orderedQuery = orderedQuery.ThenBy(iO => iO.Data.Name, ascending);
                        break;
                    case DownloadVerifySortOption.Name:
                        orderedQuery = orderedQuery.ThenBy(iO => iO.Data.Name, ascending);
                        break;
                    case DownloadVerifySortOption.Crc:
                        orderedQuery = orderedQuery.ThenBy(iO => iO.Data.Crc, ascending);
                        break;
                    case DownloadVerifySortOption.Size:
                        orderedQuery = orderedQuery.ThenBy(iO => iO.Data.Size, ascending);
                        break;
                    default:
	                    throw new TableTreeUnknownSortOptionsException($"Unknown Sort Option:{sortOption}");
	                    break;
                }
            }

            iRoot.children = orderedQuery.Cast<TreeViewItem> ().ToList ();
        }
        
        /// <summary>
        /// 初始化排序
        /// </summary>
        /// <param name="iHeaderColumns">头部列</param>
        /// <param name="iRows">行列表</param>
        /// <param name="iColumnIndexes">列索引列表</param>
        /// <returns>可排序的列表</returns>
        protected override IOrderedEnumerable<TreeViewRow<DownloadVerifyElement>> InitialOrder(
            MultiColumnHeader iHeaderColumns, IEnumerable<TreeViewRow<DownloadVerifyElement>> iRows, 
            int[] iColumnIndexes)
        {
            var sortColIndex = _sortOptions[iColumnIndexes[0]];
            var ascending = iHeaderColumns.IsSortedAscending(iColumnIndexes[0]);
            switch (sortColIndex)
            {
                case DownloadVerifySortOption.Id:
                    return iRows.Order(iO => iO.Data.Name, ascending);
                case DownloadVerifySortOption.Name:
                    return iRows.Order(iO => iO.Data.Name, ascending);
                case DownloadVerifySortOption.Crc:
                    return iRows.Order(iO => iO.Data.Crc, ascending);
                case DownloadVerifySortOption.Size:
                    return iRows.Order(iO => iO.Data.Size, ascending);
                default:
                    throw new TableTreeUnknownColumnException($"Unknown Sort Col Index:{sortColIndex}");
                    break;
            }
        }

#endregion
        
#endregion

#region Contents

		private GUIContent _originVerContent = null;
		private GUIContent _patchVerContent = null;
		private GUIContent _descVerContent = null;
        
		private GUIContent _totalSizeContent = null;
		private GUIContent _checkCodeContent = null;
		private GUIContent _totalCountContent = null;
		
		private GUIContent _dateContent = null;
		private GUIContent _authorContent = null;
		
		
		private GUIContent _downloadDirContent = null;

		/// <summary>
		/// 初始化GUI Content
		/// </summary>
		protected override void InitGuiContents()
		{
			base.InitGuiContents();
					
			_originVerContent = UtilsGUIEx.CreateGuiContent("母包版本");
			_patchVerContent = UtilsGUIEx.CreateGuiContent("补丁版本");
			_descVerContent = UtilsGUIEx.CreateGuiContent("Desc");
            
			_totalSizeContent = UtilsGUIEx.CreateGuiContent("总大小");
			_checkCodeContent = UtilsGUIEx.CreateGuiContent("校验码(Crc)");
			_totalCountContent = UtilsGUIEx.CreateGuiContent("文件数");
			
			_dateContent = UtilsGUIEx.CreateGuiContent("日期");
			_authorContent = UtilsGUIEx.CreateGuiContent("Author");
			_downloadDirContent = UtilsGUIEx.CreateGuiContent("下载目录");
		}

#endregion

#region Draw
        
        /// <summary>
        /// 绘制窗体Body
        /// </summary>
        /// <param name="iRect">制矩形范围</param>
        /// <param name="iEvent">Event</param>
        /// <returns>制矩形范围</returns>
        protected override Rect DrawWinBody(Rect iRect, Event iEvent)
        {
            var displayRect = iRect;

            var headerRect = displayRect;
            headerRect.yMax = headerRect.yMin + HeaderHeight + LocalTmpDirHeight;
            headerRect = DrawWinHeader(headerRect, iEvent);

            var searchBarRect = headerRect;
            searchBarRect.yMin = headerRect.yMax + VerticalSpacing;
            searchBarRect.yMax = searchBarRect.yMin + SingleLineHeight;
            if (Searchable)
            {
	            TableTree.SearchKey = SearchBar.OnGUI (searchBarRect, TableTree.SearchKey);
            }

            var treeRect = searchBarRect;
            treeRect.yMin = searchBarRect.yMax + VerticalSpacing;
            treeRect.yMax = displayRect.yMax;
            TableTree.DrawSelf(treeRect, iEvent);
		    
            return displayRect;
        }

        /// <summary>
        /// 绘制窗体Body
        /// </summary>
        /// <param name="iRect">制矩形范围</param>
        /// <param name="iEvent">Event</param>
        /// <returns>制矩形范围</returns>
        private Rect DrawWinHeader(Rect iRect, Event iEvent)
        {
	        var displayRect = iRect;
	        var bgRect = UtilsGUIEx.DrawGenericBg(displayRect, iEvent);

	        var widthTmp = (bgRect.width - HorizontalSpacing * 4) / 3;
	        var leftBgRect = bgRect;
	        leftBgRect.x += HorizontalSpacing;
	        leftBgRect.width = widthTmp;
	        leftBgRect.yMin += VerticalSpacing;
	        leftBgRect.yMax = leftBgRect.yMin + HeaderHeight - 1;
	        leftBgRect = UtilsGUIEx.DrawGenericBg(leftBgRect, iEvent);

	        var originVerRect = leftBgRect;
	        originVerRect.xMin += HorizontalSpacing;
	        originVerRect.xMax -= HorizontalSpacing;
	        originVerRect.yMin += VerticalSpacing;
	        originVerRect.height = SingleLineHeight;
	        originVerRect = UtilsGUIEx.DrawLabel(originVerRect, iEvent, _originVerContent,
		        UtilsGUIEx.CreateGuiContent(Data.OriginVer.Short));

	        var patchVerRect = originVerRect;
	        patchVerRect.y = originVerRect.yMax + VerticalSpacing;
	        patchVerRect = UtilsGUIEx.DrawLabel(patchVerRect, iEvent, _patchVerContent,
		        UtilsGUIEx.CreateGuiContent(Data.PathVer.Short));

	        var descVerRect = patchVerRect;
	        descVerRect.y = patchVerRect.yMax + VerticalSpacing;
	        descVerRect = UtilsGUIEx.DrawLabel(descVerRect, iEvent, _descVerContent,
		        UtilsGUIEx.CreateGuiContent($"{Data.DescVer}"));

	        var midBgRect = leftBgRect;
	        midBgRect.x = leftBgRect.xMax + HorizontalSpacing;
	        midBgRect = UtilsGUIEx.DrawGenericBg(midBgRect, iEvent);

	        var totalSizeRect = midBgRect;
	        totalSizeRect.xMin += HorizontalSpacing;
	        totalSizeRect.xMax -= HorizontalSpacing;
	        totalSizeRect.yMin += VerticalSpacing;
	        totalSizeRect.height = SingleLineHeight;
	        var totalSizeTxt = UtilsMath.GetDataDisplaySize(Data.TotalSize, false);
	        totalSizeRect = UtilsGUIEx.DrawLabel(totalSizeRect, iEvent, _totalSizeContent,
		        UtilsGUIEx.CreateGuiContent(totalSizeTxt));
	        
	        var checkCodeRect = totalSizeRect;
	        checkCodeRect.y = totalSizeRect.yMax + VerticalSpacing;
	        checkCodeRect = UtilsGUIEx.DrawLabel(checkCodeRect, iEvent, _checkCodeContent,
		        UtilsGUIEx.CreateGuiContent($"{Data.Crc}"));
            
	        var totalCountRect = checkCodeRect;
	        totalCountRect.y = checkCodeRect.yMax + VerticalSpacing;
	        totalCountRect = UtilsGUIEx.DrawLabel(totalCountRect, iEvent, _totalCountContent,
		        UtilsGUIEx.CreateGuiContent($"{Data.TotalCount}"));

	        var rightBgRect = midBgRect;
	        rightBgRect.x = midBgRect.xMax + HorizontalSpacing;
	        rightBgRect = UtilsGUIEx.DrawGenericBg(rightBgRect, iEvent);

	        var dateRect = rightBgRect;
	        dateRect.xMin += HorizontalSpacing;
	        dateRect.xMax -= HorizontalSpacing;
	        dateRect.yMin += VerticalSpacing;
	        dateRect.height = SingleLineHeight;
	        dateRect = UtilsGUIEx.DrawLabel(dateRect, iEvent, _dateContent,
		        UtilsGUIEx.CreateGuiContent(Data.Date));
	        
	        var authorRect = dateRect;
	        authorRect.y = dateRect.yMax + VerticalSpacing;
	        authorRect = UtilsGUIEx.DrawLabel(authorRect, iEvent, _authorContent,
		        UtilsGUIEx.CreateGuiContent(Data.Author));

	        var downloadDirBgRect = displayRect;
	        downloadDirBgRect.xMin += HorizontalSpacing;
	        downloadDirBgRect.xMax -= HorizontalSpacing;
	        downloadDirBgRect.yMin = rightBgRect.yMax + 1;
	        downloadDirBgRect.yMax -= VerticalSpacing;
	        downloadDirBgRect = UtilsGUIEx.DrawGenericBg(downloadDirBgRect, iEvent);

	        var downloadLabelRect = downloadDirBgRect;
	        downloadLabelRect.xMin += HorizontalSpacing;
	        downloadLabelRect.width = DownloadDirLabelWidth;
	        downloadLabelRect = UtilsGUIEx.DrawLabel(downloadLabelRect, iEvent, _downloadDirContent);

	        var downloadDirRect = downloadDirBgRect;
	        downloadDirRect.xMin = downloadLabelRect.xMax + HorizontalSpacing;
	        downloadDirRect.xMax = downloadDirBgRect.xMax - DownloadBrowseBtnWidth - HorizontalSpacing * 2;
	        downloadDirRect = UtilsGUIEx.DrawLabel(downloadDirRect, iEvent, UtilsGUIEx.CreateGuiContent(Data.DownloadDir));

	        var downloadBrowseBtnRect = downloadDirRect;
	        downloadBrowseBtnRect.xMin = downloadDirRect.xMax + HorizontalSpacing;
	        downloadBrowseBtnRect.xMax = downloadDirBgRect.xMax - HorizontalSpacing;
	        downloadBrowseBtnRect = UtilsGUIEx.DrawBrowseButton(downloadBrowseBtnRect, iEvent, Data.DownloadDir,
		        iBrowseDir =>
		        {
			        if (UtilsString.Diff(iBrowseDir, Data.DownloadDir))
			        {
				        Data.DownloadDir = iBrowseDir;
			        }
		        }, false);
	        
	        return displayRect;
        }
        
        /// <summary>
        /// 绘制TableTree的列
        /// </summary>
        /// <param name="iRect">绘制矩形范围</param>
        /// <param name="iVerifyElement">验证用Element</param>
        /// <param name="iRowIndex">行索引</param>
        /// <param name="iColumnIndex">列索引</param>
        protected override void DrawTableTreeColumn(Rect iRect, DownloadVerifyElement iVerifyElement, int iRowIndex, int iColumnIndex)
        {
            var column = (DownloadVerifyColumns)iColumnIndex;
            switch (column)
            {
                case DownloadVerifyColumns.Id:
                {
                    GUI.Label(iRect, UtilsGUIEx.CreateGuiContent($"{iVerifyElement.Id}"), GuiExHelper.MiddleCenterLabel);
                }
                    break;
            }
        }
        
#endregion

    }
}
